#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <cerrno>
#include <vector>
#include <unordered_map>
#include <cassert>
#include "log.hpp"
#include "Sock.hpp"
#include "Epoll.hpp"
#include "Protocal.hpp"

class TcpServer;
class Connection;

using func_t = std::function<void (Connection *)>;
using callback_t = std::function<void (Connection *, std::string& request)>;

class Connection
{
public:
    Connection(int sock = -1)
        :_sock(sock)
        ,_tsvr(nullptr)
    {}

    void SetCallBack(func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        _recv_cb = recv_cb;
        _send_cb = send_cb;
        _except_cb = except_cb;
    }

    ~Connection()
    {}
public:
    int _sock;
    // 三个回调方法
    func_t _recv_cb;
    func_t _send_cb;
    func_t _except_cb;
    
    // 接受缓冲区和发送缓冲区
    std::string _inbuffer;
    std::string _outbuffer;

    TcpServer* _tsvr;  // 设置回调
};

class TcpServer
{
    const static int gport = 8080;
    const static int gnum = 128;
public:
    TcpServer(int  port = gport)
        :_port(port)
        ,_revs_num(gnum)
    {
        // 1.创建listensock
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);

        // 2.创建epoll
        _poll.CreateEpoll();
        std::cout << "epoll create success" << std::endl;
        // 3.把listensock放入epoll中
        AddConnection(_listensock, std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
        std::cout << "_listensock add success" << std::endl;
        // 4.构建一个获取事件的缓冲区
        _revs = new struct epoll_event[_revs_num];
    }

    void AddConnection(int sock, func_t recv_cb, func_t send_cb, func_t except_cb)
    {
        Sock::SetNonBlock(sock);   // 把套接字设成非阻塞状态

        // 1.构建conn对象,封装sock
        Connection* conn = new Connection(sock);
        conn->SetCallBack(recv_cb, send_cb, except_cb);
        conn->_tsvr = this;

        // 2.添加sock到epoll中
        _poll.AddsockEpoll(sock, EPOLLIN | EPOLLET);  // 多路转接,一般都是对读取事件的关心,写入事件按需打开

        // 3.将对应的Connection* 对象的指针添加到映射表中
        _connection.insert(std::make_pair(sock, conn));
    }

    void Accepter(Connection* conn)
    {
        while (true)
        {
            std::string client_ip;
            uint16_t client_port;
            int accept_errno = 0;
            int sock = Sock::Accpet(conn->_sock, &client_port, &client_ip, &accept_errno);

            if (sock < 0)
            {
                if (accept_errno == EAGAIN || accept_errno == EWOULDBLOCK)
                    break;
                else if (accept_errno == EINTR)
                    continue;
                else
                {
                    // accept 失败
                    logMessage(WARNING, "accept error, %d: %s", errno, strerror(errno));
                    break;
                }
            }

            if (sock >= 0)
            {
                // 把sock托管给TcpServer
                AddConnection(sock, std::bind(&TcpServer::Recver, this, std::placeholders::_1), 
                            std::bind(&TcpServer::Sender, this, std::placeholders::_1), 
                            std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
                logMessage(NORMAL, "accept client %s: %d success, add to TcpServer success, sock: %d",
                            client_ip.c_str(), client_port, sock);
            }
        }
    }
    
    void Recver(Connection* conn)
    {
        const int num = 1024;
        bool err = false;
        while (true)
        {
            char buffer[num];
            ssize_t n = recv(conn->_sock, buffer, sizeof(buffer) - 1, 0);
            if (n < 0)
            {
                if (errno == ERROR || errno == EWOULDBLOCK)
                    break; // 正常的,没数据
                else if (errno == EINTR)
                    continue;  // 中断
                else
                {
                    // 读取失败
                    logMessage(ERROR, "recv errno, %d: %s", errno, strerror(errno));
                    conn->_except_cb(conn);
                    err = true;
                    break;
                }
            }
            else if (n == 0)
            {
                logMessage(DEBUG, "client[%d] quit, server close [%d]", conn->_sock, conn->_sock);
                conn->_except_cb(conn);
                err = true;
                break;
            }
            else
            {
                // 读取成功
                buffer[n] = 0;
                conn->_inbuffer += buffer;
            }
        }

        logMessage(DEBUG, "conn->_inbuffer[%d]: %s", conn->_sock, conn->_inbuffer.c_str());
        if (!err)
        {
            std::vector<std::string> message;
            SpeliteMessage(conn->_inbuffer, &message);
            // 保证拿走的是一个完整的报文
            for (auto& msg : message)
                _cb(conn, msg);
        }
    }

    void Sender(Connection* conn)
    {
        while (true)
        {
            ssize_t n = send(conn->_sock, conn->_outbuffer.c_str(), conn->_outbuffer.size(), 0);
            if (n > 0)
            {
                conn->_outbuffer.erase(0, n);
                if (conn->_outbuffer.empty()) break;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                    break;
                else if (errno = EINTR)
                    continue;
                else
                {
                    logMessage(ERROR, "send error, %d: %s", errno, strerror(errno));
                    conn->_except_cb(conn);
                    break;
                }
            }
        }

        if (conn->_outbuffer.empty())
            EnableReadWrite(conn, true, false);
        else
            EnableReadWrite(conn, true, true);
    }

    void EnableReadWrite(Connection* conn, bool readable, bool writeable)
    {
        uint32_t events = ((readable ? EPOLLIN : 0) | (writeable ?  EPOLLOUT : 0));
        bool res = _poll.CtlEpoll(conn->_sock, events);
        assert(res);
    }

    void Excepter(Connection* conn)
    {
        if (!IsConnectionExists(conn->_sock))
            return ;
        // 1.从epoll中移除
        bool res = _poll.DelFronEpoll(conn->_sock);
        assert(res);

        // 2.从unordered_map中移除
        _connection.erase(conn->_sock);

        // 3.close
        close(conn->_sock);

        // 4.delete conn;
        delete conn;

        logMessage(DEBUG, "Except 回收完毕, 所有异常情况");
    }

    bool IsConnectionExists(int sock)
    {
        auto iter = _connection.find(sock);
        if (iter == _connection.end())
            return false;
        else    return true;
    }

    void start(callback_t cb)
    {
        _cb = cb;
        while (true)
        {
            LoopOnce();
        }
    }

    void LoopOnce()
    {
        int n = _poll.WaitEpoll(_revs, _revs_num);
        for (int i = 0; i < n; i++)
        {
            int sock = _revs[i].data.fd;
            uint32_t revents =  _revs[i].events;

            // 所有的异常事件全部交给read和write统一处理
            if (revents & EPOLLERR)
                revents |= (EPOLLIN | EPOLLOUT);
            if (revents & EPOLLHUP)
                revents |= (EPOLLIN | EPOLLOUT);
            
            if (revents & EPOLLIN)
            {
                if (IsConnectionExists(sock) && _connection[sock]->_recv_cb != nullptr)
                    _connection[sock]->_recv_cb(_connection[sock]);
            }

            if (revents & EPOLLOUT)
            {
                if (IsConnectionExists(sock) && _connection[sock]->_send_cb != nullptr)
                    _connection[sock]->_send_cb(_connection[sock]);
            }
        }
    }

    ~TcpServer()
    {
        if (_listensock > 0) close(_listensock);
        if (_revs)  delete[] _revs;
    }
private:
    int _listensock;
    int _port;
    Epoll _poll;

    std::unordered_map<int, Connection*> _connection;
    struct epoll_event* _revs;
    int _revs_num;

    // 上层业务
    callback_t _cb;
};

